#include "CTriangleSelector.h"
#include "CBlockSceneNode.h"
#include "CTile.h"
#include "CRegionSceneNode.h"

CTriangleSelector::CTriangleSelector(CTile *tile)
: Tile(tile)
{
	update();
}

CTriangleSelector::CTriangleSelector(aabbox3df box)
: Tile(0)
{
	vector3df edges[8];
	Triangles.set_used(12);
	box.getEdges(edges);

	Triangles[0].set( edges[3], edges[0], edges[2]);
	Triangles[1].set( edges[3], edges[1], edges[0]);

	Triangles[2].set( edges[3], edges[2], edges[7]);
	Triangles[3].set( edges[7], edges[2], edges[6]);

	Triangles[4].set( edges[7], edges[6], edges[4]);
	Triangles[5].set( edges[5], edges[7], edges[4]);

	Triangles[6].set( edges[5], edges[4], edges[0]);
	Triangles[7].set( edges[5], edges[0], edges[1]);

	Triangles[8].set( edges[1], edges[3], edges[7]);
	Triangles[9].set( edges[1], edges[7], edges[5]);

	Triangles[10].set(edges[0], edges[6], edges[2]);
	Triangles[11].set(edges[0], edges[4], edges[6]);
}

void CTriangleSelector::update(void) const
{
	if(!Tile) return;
	if(!Tile->Block->areTilesUpdated())
		Tile->Block->updateTiles();

	if(!Tile->Visible)
	{
		Triangles.clear();
		Triangles.set_used(0);
		return;
	}
	else
	{
		if(/*Tile->getTileSizeType() == ETST_DYNAMIC &&*/ Tile->Resource)
		{
			if(Tile->Resource->Mesh)
			{
				const u32 cnt = Tile->Resource->Mesh->getMeshBufferCount();
				u32 totalFaceCount = 0;
				for (u32 j=0; j<cnt; ++j)
					totalFaceCount += Tile->Resource->Mesh->getMeshBuffer(j)->getIndexCount();
				totalFaceCount /= 3;
				Triangles.reallocate(totalFaceCount);

				matrix4 m = Tile->getAbsoluteTransformation() * Tile->Resource->getTransformation();


				for (u32 i=0; i<cnt; ++i)
				{
					const IMeshBuffer* buf = Tile->Resource->Mesh->getMeshBuffer(i);

					const u32 idxCnt = buf->getIndexCount();
					const u16* const indices = buf->getIndices();

					for (u32 j=0; j<idxCnt; j+=3)
					{
						vector3df a = buf->getPosition(indices[j+0]);
						vector3df b = buf->getPosition(indices[j+1]);
						vector3df c = buf->getPosition(indices[j+2]);
						m.transformVect(a);
						m.transformVect(b);
						m.transformVect(c);
			//			Tile->getAbsoluteTransformation().transformVect(a);
			//			Tile->getAbsoluteTransformation().transformVect(b);
			//			Tile->getAbsoluteTransformation().transformVect(c);
						Triangles.push_back(core::triangle3df(
								a,
								b,
								c));
					}
				}
			}
		}
		else
		{
			vector3df edges[8];
			Triangles.set_used(12);
			Tile->TransformedBoundingBox.getEdges(edges);

			Triangles[0].set( edges[3], edges[0], edges[2]);
			Triangles[1].set( edges[3], edges[1], edges[0]);

			Triangles[2].set( edges[3], edges[2], edges[7]);
			Triangles[3].set( edges[7], edges[2], edges[6]);

			Triangles[4].set( edges[7], edges[6], edges[4]);
			Triangles[5].set( edges[5], edges[7], edges[4]);

			Triangles[6].set( edges[5], edges[4], edges[0]);
			Triangles[7].set( edges[5], edges[0], edges[1]);

			Triangles[8].set( edges[1], edges[3], edges[7]);
			Triangles[9].set( edges[1], edges[7], edges[5]);

			Triangles[10].set(edges[0], edges[6], edges[2]);
			Triangles[11].set(edges[0], edges[4], edges[6]);
		}
	}
}

void CTriangleSelector::getTriangles(triangle3df* triangles,
					s32 arraySize, s32& outTriangleCount, 
					const matrix4* transform) const
{
	//update();

	s32 cnt = Triangles.size();
	if (cnt > arraySize)
		cnt = arraySize;

	matrix4 mat;

	if (transform)
		mat = *transform;

	for (s32 i=0; i<cnt; ++i)
	{
		mat.transformVect( triangles[i].pointA, Triangles[i].pointA );
		mat.transformVect( triangles[i].pointB, Triangles[i].pointB );
		mat.transformVect( triangles[i].pointC, Triangles[i].pointC );
	}

	outTriangleCount = cnt;
}



//! Gets all triangles which lie within a specific bounding box.
void CTriangleSelector::getTriangles(triangle3df* triangles, 
					s32 arraySize, s32& outTriangleCount, 
					const aabbox3d<f32>& box,
					const matrix4* transform) const
{
	// return all triangles
	return getTriangles(triangles, arraySize, outTriangleCount, transform);
}


//! Gets all triangles which have or may have contact with a 3d line.
void CTriangleSelector::getTriangles(triangle3df* triangles,
					s32 arraySize, s32& outTriangleCount,
					const line3d<f32>& line,
					const matrix4* transform) const
{
	// return all triangles
	return getTriangles(triangles, arraySize, outTriangleCount, transform);
}


//! Returns amount of all available triangles in this selector
s32 CTriangleSelector::getTriangleCount() const
{
	return Triangles.size();
}